#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>

#define BACKLIGHT_BASE "/sys/class/backlight"
#define BRIGHTNESS_FILE "brightness"
#define MAX_BRIGHTNESS_FILE "max_brightness"

// Find the first available backlight brightness file
char* find_brightness_path() {
    DIR *dir = opendir(BACKLIGHT_BASE);
    if (!dir) {
        perror("Failed to open backlight directory");
        return NULL;
    }

    struct dirent *entry;
    static char brightness_path[PATH_MAX];
    static char max_brightness_path[PATH_MAX];

    while ((entry = readdir(dir)) != NULL) {
        // Skip . and ..
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            continue;

        // Build full paths
        snprintf(brightness_path, PATH_MAX, "%s/%s/%s",
                BACKLIGHT_BASE, entry->d_name, BRIGHTNESS_FILE);
        snprintf(max_brightness_path, PATH_MAX, "%s/%s/%s",
                BACKLIGHT_BASE, entry->d_name, MAX_BRIGHTNESS_FILE);

        // Check if both files exist
        FILE *brightness_fd = fopen(brightness_path, "r");
        FILE *max_fd = fopen(max_brightness_path, "r");

        if (brightness_fd && max_fd) {
            fclose(brightness_fd);
            fclose(max_fd);
            closedir(dir);
            return brightness_path;
        }

        if (brightness_fd) fclose(brightness_fd);
        if (max_fd) fclose(max_fd);
    }

    closedir(dir);
    fprintf(stderr, "No backlight brightness file found\n");
    return NULL;
}

// Get current brightness value
int get_current_brightness(const char *path) {
    FILE *fd = fopen(path, "r");
    if (!fd) {
        perror("Failed to open brightness file for reading");
        return -1;
    }

    int val;
    if (fscanf(fd, "%d", &val) != 1) {
        perror("Failed to read brightness value");
        fclose(fd);
        return -1;
    }

    fclose(fd);
    return val;
}

// Get maximum brightness value
int get_max_brightness(const char *brightness_path) {
    // Replace "brightness" with "max_brightness" in path
    char max_path[PATH_MAX];
    strncpy(max_path, brightness_path, PATH_MAX);
    char *last_slash = strrchr(max_path, '/');
    if (last_slash) {
        strcpy(last_slash + 1, MAX_BRIGHTNESS_FILE);
    } else {
        fprintf(stderr, "Invalid brightness path format\n");
        return -1;
    }

    FILE *fd = fopen(max_path, "r");
    if (!fd) {
        perror("Failed to open max_brightness file");
        return -1;
    }

    int max_val;
    if (fscanf(fd, "%d", &max_val) != 1) {
        perror("Failed to read max brightness value");
        fclose(fd);
        return -1;
    }

    fclose(fd);
    return max_val;
}

// Set new brightness value
int set_brightness(const char *path, int new_val) {
    FILE *fd = fopen(path, "w");
    if (!fd) {
        perror("Failed to open brightness file for writing");
        return -1;
    }

    if (fprintf(fd, "%d\n", new_val) < 0) {
        perror("Failed to write new brightness value");
        fclose(fd);
        return -1;
    }

    fclose(fd);
    return 0;
}

void print_usage(const char *prog_name) {
    fprintf(stderr, "\nbrightness control util program, require root permission to change the /sys/class/backlight/.../brightness file value\n");
    fprintf(stderr, "Usage: %s <U|up|-u or |D|down|-d> <STEP_NUM>\n", prog_name);
    fprintf(stderr, "  U: Increase brightness by STEP_NUM\n");
    fprintf(stderr, "  D: Decrease brightness by STEP_NUM\n");
    fprintf(stderr, "Example Usage:\n");
    fprintf(stderr, "%s U|up|-u 20\n", prog_name);
    fprintf(stderr, "%s D|down|-d 20\n", prog_name);
}

int main(int argc, char *argv[]) {
    // Find brightness file path
    char *brightness_path = find_brightness_path();
    if (!brightness_path) {
        return 1;
    }

    // Get current and max brightness
    int current = get_current_brightness(brightness_path);
    if (current < 0) return 1;

    int max_val = get_max_brightness(brightness_path);
    if (max_val < 0) return 1;

    // Handle no arguments (print current status)
    if (argc == 1) {
	printf("=======================================================================\n");	
        printf("brightness:\n current value:\n %d\n max value:\n %d\n", current, max_val);
	printf("=======================================================================\n");	
	print_usage(argv[0]);
        return 0;
    }

    // Validate arguments
    if (argc != 3) {
        print_usage(argv[0]);
        return 1;
    }

    // Parse step number
    char *endptr;
    long step = strtol(argv[2], &endptr, 10);
    if (*endptr != '\0' || step <= 0) {
        fprintf(stderr, "[error]: Invalid step number: %s\n", argv[2]);
        print_usage(argv[0]);
        return 1;
    }

    // Calculate new brightness
    int new_val;
    if (strcmp(argv[1], "U") == 0 || strcmp(argv[1], "up") == 0 || strcmp(argv[1], "-u") == 0) {
        new_val = current + step;
        if (new_val > max_val) {
            new_val = max_val;
            printf("[error]: out of range, set the value to %d\n", max_val);
        } else {
	    printf("[ok]: current brightness value: %d\n", new_val);
	}
    } else if (strcmp(argv[1], "D") == 0 || strcmp(argv[1], "down") == 0 || strcmp(argv[1], "-d") == 0) {
        new_val = current - step;
        if (new_val < 0) {
            new_val = 0;
            printf("[error]: out of range, set the value to 0\n");
        } else {
	    printf("[ok]: current brightness value: %d\n", new_val);
	}
    } else {
        fprintf(stderr, "[error]: Invalid operation: %s\n", argv[1]);
        print_usage(argv[0]);
        return 1;
    }

    // Set new brightness
    if (set_brightness(brightness_path, new_val) != 0) {
        return 1;
    }

    return 0;
}
